﻿using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using AuctionClassLibrary;

namespace Laks
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    [Serializable]
    public partial class MainWindow
    {
        private const int PORT = 31415;
        private decimal _currentBid, _myBid;
        private readonly IPEndPoint _serverAddress;
        private Socket _server;
        private Thread _auctionThread;
        private readonly ClientThread _clientThread;
        private NetworkStream _networkStream;
        private StreamWriter _streamWriter;
        private StreamReader _streamReader;
        private string _name;

        private delegate void lblNameUpdateDelegate(Auction auction);
        private delegate void txtDescriptionUpdateDelegate(Auction auction);
        private delegate void lblStartingPriceUpdateDelegate(Auction auction);
        private delegate void lblEstimatedPriceUpdateDelegate(Auction auction);
        private delegate void lblCurrentPriceGotBidDelegate(string bid);
        private delegate void tbHistorikGotBidDelegate(DateTime time, string ip, string bid);
        private delegate void tbHistorikHammerDelegate(DateTime time, string message);
        private delegate void lblCountDelegate(string number);
        
        public MainWindow(string name)
        {
            InitializeComponent();
            _clientThread = new ClientThread();
            _clientThread.AuctionReceiveEvent += new AuctionReceiveDelegate(this.AuctionReceiveHandle);
            _clientThread.GotBidEvent += new GotBidDelegate(GotBidHandle);
            _clientThread.HammerEvent += new HammerDelegate(this.HammerHandle);
            _clientThread.CountClientsEvent += new CountClientsDelegate(this.CountClientsHandle);
            _name = name;
            _serverAddress = new IPEndPoint(IPAddress.Parse("127.0.0.1"), PORT);
            Connect(); // Connect
            txtBid.Focus();
            _myBid = 0;

            // AutoScrollViewer
            var timer = new DispatcherTimer { Interval = new TimeSpan(0, 0, 2) };
            timer.Tick += ((sender, e) => { if (scrollViewer.VerticalOffset == scrollViewer.ScrollableHeight) { scrollViewer.ScrollToEnd(); } });
            timer.Start();
        }

        private void CountClientsHandle(string number)
        {
            lblCount.Dispatcher.BeginInvoke(new lblCountDelegate(this.lblCountHandle), number);
        }
        private void lblCountHandle(string number)
        {
            lblCount.Content = number;
        }
        //private void BidReceiveHandle(DateTime date, int id, decimal bid) { TbHistorik.Dispatcher.BeginInvoke(new GotBid(BroadcastBid), date, id, bid); }
        private void BroadcastBid(DateTime date, int id, decimal bid)
        {
            TbHistorik.Inlines.Add(new Run("\r"));
            TbHistorik.Inlines.Add(new Run("[" + date.ToString("HH:mm:ss") + "] ") { Foreground = Brushes.Purple });
            TbHistorik.Inlines.Add(new Run(id + ": ") { Foreground = Brushes.Red });
            TbHistorik.Inlines.Add(new Run(bid.ToString()) { TextDecorations = TextDecorations.Underline });
        }
        private void btnBid_Click(object sender, RoutedEventArgs e)
        {
            if (_currentBid == _myBid)
            {
                ErrorMessage("Du kan ikke byde over dig selv, cunt. :)");
                return;
            }
            // Create string:
            var s = txtBid.Text;
            _myBid = decimal.Parse(s);

            if (_myBid <= _currentBid) { ErrorMessage("Dit bud må ikke være lavere eller lig med start- og/eller nuværende bud. Prøv igen."); }
            else
            {
                //  _clientThread.SendToServer(s);
                _streamWriter.WriteLine(_name + ";" + s + ";bid");
                _streamWriter.Flush();
            }
            txtBid.Clear();
        }
        private void ErrorMessage(string message)
        {
            TbHistorik.Inlines.Add(new Run("\r"));
            TbHistorik.Inlines.Add(new Run("[" + DateTime.Now.ToString("HH:mm:ss") + "] ") { Foreground = Brushes.Purple });
            TbHistorik.Inlines.Add(new Run("Fejl: ") { Foreground = Brushes.Red, FontWeight = FontWeights.Bold });
            TbHistorik.Inlines.Add(new Run(message) { Foreground = Brushes.Red, FontWeight = FontWeights.Bold });
        }

        private void AuctionReceiveHandle(Auction auction, string lastPrice)
        {
            lblEstimatedPrice.Dispatcher.BeginInvoke(
                new lblEstimatedPriceUpdateDelegate(lblEstimatedPriceUpdateHandle), auction);
            lblName.Dispatcher.BeginInvoke(new lblNameUpdateDelegate(lblNameUpdateHandle), auction);
            txtDescription.Dispatcher.BeginInvoke(new txtDescriptionUpdateDelegate(txtDescriptionUpdateHandle),
                                                  auction);
            lblStartingPrice.Dispatcher.BeginInvoke(
                new lblStartingPriceUpdateDelegate(lblStartingPriceUpdateHandle), auction);
            lblCurrentPrice.Dispatcher.BeginInvoke(new lblCurrentPriceGotBidDelegate(lblCurrentPriceHandle),
                                                   lastPrice);

            // Set title and image dynamically:
            Dispatcher.BeginInvoke(new Action(() =>
                {
                    Title = auction.Name + " - Laks Auktionshus";
                    image.Source = new BitmapImage(new Uri(@"Images/" + auction.Name + ".jpg", UriKind.Relative));
                }));
        }

        private void lblNameUpdateHandle(Auction auction) { lblName.Content = auction.Name; }
        private void lblStartingPriceUpdateHandle(Auction auction) { lblStartingPrice.Content = "DKK " + auction.StartPrice.ToString(); }
        private void lblEstimatedPriceUpdateHandle(Auction auction)
        {
            lblEstimatedPrice.Content = "DKK " + auction.EstimatedPrice.ToString();

            //Clear tbHistorik efter en auktion
            TbHistorik.Text = String.Empty;
            //txtBid åbnes igen efter en nye auktion startet
            if (_clientThread.CloseAuction == false)
            {
                btnBid.IsEnabled = true;
                txtBid.IsEnabled = true;
                txtBid.Focus();
            }
        }
        private void txtDescriptionUpdateHandle(Auction auction) { txtDescription.Text = auction.Description; }

        private void Connect()
        {
            _server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            try { _server.Connect(_serverAddress); }
            catch (SocketException ex) { MessageBox.Show(ex.Message); Close(); } // Close the whole application:
            _networkStream = new NetworkStream(_server);
            _streamWriter = new StreamWriter(_networkStream);
            _streamReader = new StreamReader(_networkStream);
            _auctionThread = new Thread(() => _clientThread.HandleAuction(_networkStream, _streamReader, _streamWriter));
            // _auctionThread = new Thread(() => _clientThread.HandleAuction(_server));
            _auctionThread.Start();
            _streamWriter.WriteLine(_name);
            _streamWriter.Flush();
            _streamWriter.WriteLine(_name + ";login");
            _streamWriter.Flush();
        }

        public void GotBidHandle(DateTime time, string ip, string bid)
        {
            lblCurrentPrice.Dispatcher.BeginInvoke(new lblCurrentPriceGotBidDelegate(lblCurrentPriceHandle), bid);
            TbHistorik.Dispatcher.BeginInvoke(new tbHistorikGotBidDelegate(tbHistorikHandle), time, ip, bid);
        }


        public void lblCurrentPriceHandle(string bid)
        {
            _currentBid = decimal.Parse(bid);
            lblCurrentPrice.Content = "DKK " + bid;
        }

        public void tbHistorikHandle(DateTime time, string ip, string bid) { BroadcastServer(time, ip, bid); }

        public void HammerHandle(DateTime time, string message)
        {
            TbHistorik.Dispatcher.BeginInvoke(new tbHistorikHammerDelegate(this.tbHistorikHammerHandle), time, message);
        }

        public void tbHistorikHammerHandle(DateTime time, string message)
        {
            //txtBid lukkes efter en auktion er færdig
            if (_clientThread.CloseAuction == true)
            {
                btnBid.IsEnabled = false;
                txtBid.IsEnabled = false;
                _clientThread.CloseAuction = false;
            }
            BroadcastServer(time, message);
        }

        private void BroadcastServer(DateTime date, string message)
        {
            TbHistorik.Inlines.Add(new Run("\r"));
            TbHistorik.Inlines.Add(new Run("[" + date.ToString("HH:mm:ss") + "] ") { Foreground = Brushes.Chocolate, FontSize = 20 });
            TbHistorik.Inlines.Add(new Run(message) { Foreground = Brushes.Chocolate, FontWeight = FontWeights.Bold, FontSize = 20 });

        }
        private void BroadcastServer(DateTime date, string name, string bid)
        {
            // _currentBid = decimal.Parse(bid);

            TbHistorik.Inlines.Add(new Run("\r"));
            TbHistorik.Inlines.Add(new Run("[" + date.ToString("HH:mm:ss") + "] ") { Foreground = Brushes.Purple });
            TbHistorik.Inlines.Add(new Run(name + ": ") { Foreground = Brushes.Red, FontWeight = FontWeights.Bold });
            TbHistorik.Inlines.Add(new Run("DKK " + bid) { TextDecorations = TextDecorations.Underline });
        }
        private void Window_Closed(object sender, EventArgs e)
        {
            _streamWriter.WriteLine(_name + ";logout");
            _streamWriter.Flush();
            _streamWriter.Close();
            _streamReader.Close();
            _networkStream.Close();
            _server.Shutdown(SocketShutdown.Both);
        }
        // A textbox that only accepts numbers:
        private void NumericOnly(object sender, TextCompositionEventArgs e)
        {
            e.Handled = IsTextNumeric(e.Text);
        }

        private static bool IsTextNumeric(string str)
        {
            var reg = new Regex("[^0-9]");
            return reg.IsMatch(str);
        }
    }
}